package l2ft.gameserver.network.l2.s2c;

import java.util.Map;

import l2ft.gameserver.Config;
import l2ft.gameserver.data.xml.holder.CharTemplateHolder;
import l2ft.gameserver.model.Creature;
import l2ft.gameserver.model.Player;
import l2ft.gameserver.model.Summon;
import l2ft.gameserver.model.base.TeamType;
import l2ft.gameserver.model.instances.FakePcInstance;
import l2ft.gameserver.model.instances.NpcInstance;
import l2ft.gameserver.model.pledge.Alliance;
import l2ft.gameserver.model.pledge.Clan;
import l2ft.gameserver.network.l2.components.NpcString;
import l2ft.gameserver.templates.CharTemplate;
import l2ft.gameserver.utils.Location;

import org.apache.commons.lang3.StringUtils;

public class NpcInfo extends L2GameServerPacket
{
	private boolean can_writeImpl = false;
	private NpcInstance _npc;
	private int _npcObjId, _npcId, running, incombat, dead, _showSpawnAnimation;
	private int _runSpd, _walkSpd, _mAtkSpd, _pAtkSpd, _rhand, _lhand, _enchantEffect;
	private int karma, pvp_flag, _abnormalEffect, _abnormalEffect2, clan_id, clan_crest_id, ally_id, ally_crest_id, _formId, _titleColor;
	private Map<Creature, Integer> _invidualAbnormals;
	private double colHeight, colRadius, currentColHeight, currentColRadius;
	private boolean _isAttackable, _isNameAbove, isFlying;
	private Location _loc;
	private String _name = StringUtils.EMPTY;
	private String _title = StringUtils.EMPTY;
	private boolean _showName;
	private int _state;
	private NpcString _nameNpcString = NpcString.NONE;
	private NpcString _titleNpcString = NpcString.NONE;
	private TeamType _team;

	public NpcInfo(NpcInstance cha, Creature attacker)
	{
		_npc = cha;
		_npcId = cha.getDisplayId() != 0 ? cha.getDisplayId() : cha.getTemplate().npcId;
		_isAttackable = attacker != null && cha.isAutoAttackable(attacker);
		_rhand = cha.getRightHandItem();
		_lhand = cha.getLeftHandItem();
		_enchantEffect = 0;
		if(Config.SERVER_SIDE_NPC_NAME || cha.getTemplate().displayId != 0 || cha.getName() != cha.getTemplate().name)
			_name = cha.getName();
		if(Config.SERVER_SIDE_NPC_TITLE || cha.getTemplate().displayId != 0 || cha.getTitle() != cha.getTemplate().title)
			_title = cha.getTitle();

		_showSpawnAnimation = cha.getSpawnAnimation();
		_showName = cha.isShowName();
		_state = cha.getNpcState();
		_nameNpcString = cha.getNameNpcString();
		_titleNpcString = cha.getTitleNpcString();

		common(cha);
	}

	public NpcInfo(Summon cha, Creature attacker)
	{
		if(cha.getPlayer() != null && cha.getPlayer().isInvisible())
			return;

		_npcId = cha.getTemplate().npcId;
		_isAttackable = cha.isAutoAttackable(attacker);
		_rhand = 0;
		_lhand = 0;
		_enchantEffect = 0;
		_showName = true;
		_name = cha.getName();
		_title = cha.getTitle();
		_showSpawnAnimation = cha.getSpawnAnimation();

		common(cha);
	}

	private void common(Creature cha)
	{
		colHeight = cha.getTemplate().collisionHeight;
		colRadius = cha.getTemplate().collisionRadius;
		currentColHeight = cha.getColHeight();
		currentColRadius = cha.getColRadius();
		_npcObjId = cha.getObjectId();
		_loc = cha.getLoc();
		_mAtkSpd = cha.getMAtkSpd();
		//
		Clan clan = cha.getClan();
		Alliance alliance = clan == null ? null : clan.getAlliance();
		//
		clan_id = clan == null ? 0 : clan.getClanId();
		clan_crest_id = clan == null ? 0 : clan.getCrestId();
		//
		ally_id = alliance == null ? 0 : alliance.getAllyId();
		ally_crest_id = alliance == null ? 0 : alliance.getAllyCrestId();

		_runSpd = cha.getRunSpeed();
		_walkSpd = cha.getWalkSpeed();
		karma = cha.getKarma();
		pvp_flag = cha.getPvpFlag();
		_pAtkSpd = cha.getPAtkSpd();
		running = cha.isRunning() ? 1 : 0;
		incombat = cha.isInCombat() ? 1 : 0;
		dead = cha.isAlikeDead() ? 1 : 0;
		_abnormalEffect = cha.getAbnormalEffect();
		_abnormalEffect2 = cha.getAbnormalEffect2();
		_invidualAbnormals = cha.getInvidualAbnormals();
		isFlying = cha.isFlying();
		_team = cha.getTeam();
		_formId = cha.getFormId();
		_isNameAbove = cha.isNameAbove();
		_titleColor = (cha.isSummon() || cha.isPet()) ? 1 : 0;

		can_writeImpl = true;
	}

	public NpcInfo update()
	{
		_showSpawnAnimation = 1;
		return this;
	}

	@Override
	protected final void writeImpl()
	{
		if(!can_writeImpl)
			return;
		
		//Fake Pc
		if(_npc != null && _npc.isFakePc())
		{
			FakePcInstance fpc = (FakePcInstance)_npc;
			writeC(0x31);
			writeD(_loc.x);
			writeD(_loc.y);
			writeD(_loc.z);
			writeD(0x00); // vehicle id
			writeD(_npc.getObjectId());
			writeS(fpc.name); // visible name
			writeD(fpc.race);
			writeD(fpc.sex);
			writeD(fpc.clazz);
			
			writeD(fpc.pdUnder);
			writeD(fpc.pdHead);
			writeD(fpc.pdRHand);
			writeD(fpc.pdLHand);
			writeD(fpc.pdGloves);
			writeD(fpc.pdChest);
			writeD(fpc.pdLegs);
			writeD(fpc.pdFeet);
			writeD(fpc.pdBack);
			writeD(fpc.pdLRHand);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00); // belt
			
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);
			writeD(0x01);
			
			writeD(fpc.pvpFlag);
			writeD(0);

			writeD(_mAtkSpd);
			writeD(_pAtkSpd);

			writeD(0x00);

			writeD(_runSpd);
			writeD(_walkSpd);
			writeD(_runSpd); // swim run speed
			writeD(_walkSpd); // swim walk speed
			writeD(_runSpd); // fly run speed
			writeD(_walkSpd); // fly walk speed
			writeD(_runSpd);
			writeD(_walkSpd);
			writeF(_npc.getMovementSpeedMultiplier()); // _activeChar.getProperMultiplier()
			writeF(_npc.getAttackSpeedMultiplier()); // _activeChar.getAttackSpeedMultiplier()

			boolean female = fpc.sex == 0 ? false : true;
			CharTemplate pctmpl = CharTemplateHolder.getInstance().getTemplate(fpc.clazz, female);
			writeF(pctmpl.collisionRadius);
			writeF(pctmpl.collisionHeight);

			writeD(fpc.hairStyle);
			writeD(fpc.hairColor);
			writeD(fpc.face);

			writeS(fpc.title); // visible title

			writeD(0x00); // clan id
			writeD(0x00); // clan crest id
			writeD(0x00); // ally id
			writeD(0x00); // ally crest id

			writeC(0x01); // standing = 1  sitting = 0
			writeC(_npc.isRunning() ? 1 : 0); // running = 1   walking = 0
			writeC(_npc.isInCombat() ? 1 : 0);
			writeC(_npc.isAlikeDead() ? 1 : 0);

			writeC(fpc.invisible); // invisible = 1  visible =0

			writeC(0x00); // 1 on strider   2 on wyvern  3 on Great Wolf  0 no mount
			writeC(0x00); //  1 - sellshop
			writeH(0x00); // cubic count
			//for (int id : allCubics)
			//    writeH(id);
			writeC(0x00); // find party members
			writeD(0x00); // abnormal effect
			writeC(0x00); // isFlying() ? 2 : 0
			writeH(0x00); //getRecomHave(): Blue value for name (0 = white, 255 = pure blue)
			writeD(1000000); // getMountNpcId() + 1000000
			writeD(fpc.clazz);
			writeD(0x00); // ?
			writeC(0x00);
			writeC(fpc.team); //team circle around feet 1= Blue, 2 = red
			writeD(0x00); // getClanCrestLargeId()
			writeC(0x00); // isNoble(): Symbol on char menu ctrl+I
			writeC(fpc.hero); // Hero Aura
			writeC(0x00); //0x01: Fishing Mode (Cant be undone by setting back to 0)
			writeD(0x00);
			writeD(0x00);
			writeD(0x00);

			writeD(fpc.nameColor);
			writeD(_loc.h);
			writeD(0x00); // pledge class
			writeD(0x00); // pledge type
			writeD(0xFFFF77);

			writeD(0x00); // cursed weapon level
			writeD(0x00); // reputation score
			writeD(0x00); // transformation id
			writeD(0x00); // agathion id
			writeD(0x01); // T2 ?
			writeD(0x00); // special effect
			/*writeD(0x00); // territory Id
			writeD(0x00); // is Disguised
			writeD(0x00); // territory Id*/ 
		}
		else
		{
		
			Player activeChar = getClient().getActiveChar();
			
			if(activeChar != null && _invidualAbnormals.containsKey(activeChar))
				_abnormalEffect2 |= _invidualAbnormals.get(activeChar);
	
			writeC(0x0c);
			//ddddddddddddddddddffffdddcccccSSddddddddccffddddccd
			writeD(_npcObjId);
			writeD(_npcId + 1000000); // npctype id c4
			writeD(_isAttackable ? 1 : 0);
			writeD(_loc.x);
			writeD(_loc.y);
			writeD(_loc.z + Config.CLIENT_Z_SHIFT);
			writeD(_loc.h);
			writeD(0x00);
			writeD(_mAtkSpd);
			writeD(_pAtkSpd);
			writeD(_runSpd);
			writeD(_walkSpd);
			writeD(_runSpd /*_swimRunSpd*//*0x32*/); // swimspeed
			writeD(_walkSpd/*_swimWalkSpd*//*0x32*/); // swimspeed
			writeD(_runSpd/*_flRunSpd*/);
			writeD(_walkSpd/*_flWalkSpd*/);
			writeD(_runSpd/*_flyRunSpd*/);
			writeD(_walkSpd/*_flyWalkSpd*/);
			writeF(1.100000023841858); // ????? ?? ???????
			writeF(_pAtkSpd / 277.478340719);
			writeF(colRadius);
			writeF(colHeight);
			writeD(_rhand); // right hand weapon
			writeD(0); //chest
			writeD(_lhand); // left hand weapon
			writeC(_isNameAbove ? 1 : 0); // 2.2: name above char 1=true ... ??; 2.3: 1 - normal, 2 - dead
			writeC(running);
			writeC(incombat);
			writeC(dead);
			writeC(_showSpawnAnimation); // invisible ?? 0=false  1=true   2=summoned (only works if model has a summon animation)
			writeD(_nameNpcString.getId());
			writeS(_name);
			writeD(_titleNpcString.getId());
			writeS(_title);
			writeD(_titleColor); // 0- ?????? ??????? ?????(???), 1 - ?????? ?????(???)/??????????? ???????? ??
			writeD(pvp_flag);
			writeD(karma); // hmm karma ??
			writeD(_abnormalEffect); // C2
			writeD(clan_id);
			writeD(clan_crest_id);
			writeD(ally_id);
			writeD(ally_crest_id);
			writeC(isFlying ? 2 : 0); // C2
			writeC(_team.ordinal()); // team aura 1-blue, 2-red
			writeF(currentColRadius); // ??? ???-?? ????????? ? colRadius
			writeF(currentColHeight); // ??? ???-?? ????????? ? colHeight
			writeD(_enchantEffect); // C4
			writeD(0x00); // writeD(_npc.isFlying() ? 1 : 0); // C6
			writeD(0x00);
			writeD(_formId);// great wolf type
			writeC(_showName ? 0x01 : 0x00); // show name
			writeC(_showName ? 0x01 : 0x00); // show title
			writeD(_abnormalEffect2);
			writeD(_state);
		}
	}
}